package com.nnnu.wsnackshop.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nnnu.wsnackshop.exception.BaseException;
import com.nnnu.wsnackshop.mapper.CouponsMapper;
import com.nnnu.wsnackshop.mapper.UserCouponsMapper;
import com.nnnu.wsnackshop.pojo.entity.CouponUsage;
import com.nnnu.wsnackshop.pojo.entity.Coupons;
import com.nnnu.wsnackshop.pojo.entity.UserCoupons;
import com.nnnu.wsnackshop.pojo.vo.CouponVO;
import com.nnnu.wsnackshop.service.ICouponUsageService;
import com.nnnu.wsnackshop.service.IUserCouponsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户优惠券 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-06-24
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserCouponsServiceImpl extends ServiceImpl<UserCouponsMapper, UserCoupons>
        implements IUserCouponsService {

    private final CouponsMapper couponsMapper;
    private final UserCouponsMapper userCouponsMapper;
    private final ICouponUsageService couponUsageService;

    // 新人优惠券ID列表
    private static final List<Integer> NEW_USER_COUPON_IDS = Arrays.asList(1, 2, 3);

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    @Retryable(retryFor = { CannotAcquireLockException.class }, backoff = @Backoff(delay = 1000))
    public List<CouponVO> issueNewUserCoupons(Integer userId) {
        log.info("为用户{}发放新人券，尝试获取锁", userId);

        // 检查用户是否已经领取过新人券
        if (!isFirstLogin(userId)) {
            log.warn("用户{}已经领取过新人券，不能重复领取", userId);
            throw new BaseException("您已经领取过新人券，不能重复领取");
        }

        List<CouponVO> issuedCoupons = new ArrayList<>();

        try {
            // 获取新人优惠券模板
            List<Coupons> newUserCoupons = couponsMapper.selectByIds(NEW_USER_COUPON_IDS);
            if (newUserCoupons.isEmpty()) {
                log.error("未找到新人优惠券模板");
                throw new BaseException("系统错误，未找到新人优惠券");
            }

            LocalDateTime now = LocalDateTime.now();

            for (Coupons coupon : newUserCoupons) {
                // 检查优惠券有效期
                if (coupon.getStartTime().isAfter(now) || coupon.getEndTime().isBefore(now)) {
                    log.warn("优惠券{}不在有效期内，跳过发放", coupon.getId());
                    continue;
                }

                // 创建用户优惠券记录
                UserCoupons userCoupon = new UserCoupons();
                userCoupon.setCouponId(coupon.getId());
                userCoupon.setUserId(userId);
                userCoupon.setAmount(coupon.getAmount());
                userCoupon.setStatus(0); // 0=未使用
                userCoupon.setCreatedAt(now);
                userCoupon.setUpdatedAt(now);

                // 保存用户优惠券记录
                try {
                    userCouponsMapper.insert(userCoupon);

                    // 转换为VO对象返回
                    CouponVO couponVO = new CouponVO();
                    BeanUtils.copyProperties(coupon, couponVO);
                    issuedCoupons.add(couponVO);

                    log.info("为用户{}发放新人券{}成功", userId, coupon.getId());
                } catch (Exception e) {
                    log.error("为用户{}发放新人券{}失败: {}", userId, coupon.getId(), e.getMessage());
                    throw new BaseException("优惠券发放失败，请稍后再试");
                }
            }
        } catch (CannotAcquireLockException e) {
            log.warn("为用户{}发放新人券时获取锁失败，将自动重试: {}", userId, e.getMessage());
            throw e; // 让Spring Retry处理重试
        } catch (Exception e) {
            log.error("为用户{}发放新人券出现错误: {}", userId, e.getMessage(), e);
            if (!(e instanceof BaseException)) {
                throw new BaseException("系统繁忙，请稍后再试");
            }
            throw e;
        }

        return issuedCoupons;
    }

    @Async("taskExecutor")
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED)
    public void issueNewUserCouponsAsync(Integer userId) {
        log.info("开始异步为用户{}发放新人券", userId);
        try {
            // 等待2秒钟，避免与主事务冲突
            Thread.sleep(3000);

            // 在单独的线程中执行发券逻辑
            List<CouponVO> coupons = issueNewUserCoupons(userId);
            log.info("异步为用户{}发放新人券成功，数量: {}", userId, coupons.size());

        } catch (Exception e) {
            log.error("异步为用户{}发放新人券失败: {}", userId, e.getMessage(), e);

        }
    }

    @Override
    @Transactional(readOnly = true)
    public boolean isFirstLogin(Integer userId) {
        // 查询用户是否有领取新人券的记录
        Long count = userCouponsMapper.selectCount(
                new LambdaQueryWrapper<UserCoupons>()
                        .eq(UserCoupons::getUserId, userId)
                        .in(UserCoupons::getCouponId, NEW_USER_COUPON_IDS));

        // 如果没有记录，说明是首次登录
        return count == 0;
    }

    @Override
    @Transactional(readOnly = true)
    public List<CouponVO> getUserAvailableCoupons(Integer userId) {
        // 获取用户可用优惠券
        List<UserCoupons> userCoupons = userCouponsMapper.getUserAvailableCoupons(userId);

        if (userCoupons.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取优惠券ID列表
        List<Integer> couponIds = userCoupons.stream()
                .map(UserCoupons::getCouponId)
                .distinct()
                .collect(Collectors.toList());

        // 查询优惠券详情
        List<Coupons> coupons = couponsMapper.selectBatchIds(couponIds);

        // 将优惠券信息与用户优惠券关联
        return userCoupons.stream().map(userCoupon -> {
            CouponVO vo = new CouponVO();

            // 找到对应的优惠券模板
            coupons.stream()
                    .filter(c -> c.getId().equals(userCoupon.getCouponId()))
                    .findFirst()
                    .ifPresent(c -> BeanUtils.copyProperties(c, vo));

            // 设置用户优惠券ID
            vo.setId(userCoupon.getId());
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean useCoupon(Integer userId, Integer userCouponId, Long orderId, String orderNo) {
        // 查询用户优惠券
        UserCoupons userCoupon = userCouponsMapper.selectById(userCouponId);

        if (userCoupon == null) {
            log.error("用户优惠券不存在: userCouponId={}", userCouponId);
            return false;
        }

        if (!userCoupon.getUserId().equals(userId)) {
            log.error("用户优惠券不属于当前用户: userCouponId={}, userId={}, actualUserId={}",
                    userCouponId, userId, userCoupon.getUserId());
            return false;
        }

        if (userCoupon.getStatus() != 0) {
            log.error("用户优惠券状态不可用: userCouponId={}, status={}", userCouponId, userCoupon.getStatus());
            return false;
        }

        // 查询优惠券模板
        Coupons coupon = couponsMapper.selectById(userCoupon.getCouponId());
        if (coupon == null) {
            log.error("优惠券模板不存在: couponId={}", userCoupon.getCouponId());
            return false;
        }

        try {
            // 更新用户优惠券状态
            LambdaUpdateWrapper<UserCoupons> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserCoupons::getId, userCouponId)
                    .eq(UserCoupons::getStatus, 0) // 确保状态为未使用
                    .set(UserCoupons::getStatus, 1); // 设置为已使用;

            update(updateWrapper);



            // 记录优惠券使用情况
           couponUsageService.recordUsage(
                    userCouponId, userId, userCoupon.getCouponId(), orderId, orderNo, userCoupon.getAmount());



            log.info("用户优惠券使用成功: userCouponId={}, orderId={}", userCouponId, orderId);
            return true;
        } catch (Exception e) {
            log.error("使用优惠券过程中出错: userCouponId={}, error={}", userCouponId, e.getMessage(), e);
            throw new RuntimeException("使用优惠券失败: " + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean returnCoupon(Integer userId, Long orderId) {
        try {
            // 查询订单使用的优惠券记录
            LambdaQueryWrapper<CouponUsage> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CouponUsage::getUserId, userId)
                    .eq(CouponUsage::getOrderId, orderId);

            CouponUsage couponUsage = couponUsageService.getOne(queryWrapper);

            if (couponUsage == null) {
                log.warn("未找到订单使用的优惠券记录: userId={}, orderId={}", userId, orderId);
                return false;
            }

            // 更新用户优惠券状态
            LambdaUpdateWrapper<UserCoupons> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserCoupons::getId, couponUsage.getUserCouponId())
                    .eq(UserCoupons::getUserId, userId)
                    .set(UserCoupons::getStatus, 0)
                    .set(UserCoupons::getUpdatedAt, LocalDateTime.now());

            update(updateWrapper);



            // 删除优惠券使用记录
           couponUsageService.deleteUsageByOrderId(userId, orderId);



            log.info("优惠券退还成功: userCouponId={}, orderId={}", couponUsage.getUserCouponId(), orderId);
            return true;
        } catch (Exception e) {
            log.error("退还优惠券过程中出错: userId={}, orderId={}, error={}", userId, orderId, e.getMessage(), e);
            throw new RuntimeException("退还优惠券失败: " + e.getMessage());
        }
    }
}